import { type Router, type RouteRecordNormalized, type RouteRecordRaw, createRouter, createWebHashHistory, createWebHistory } from 'vue-router';
import { cloneDeep, omit } from 'lodash-es';

/** 路由模式 */
/* 
  ? SPA 只有一个html文件,一旦页面加载完成不会因为用户的操作进行加载或跳转本身url并没有变化而是通过JS改变内容
  ?     服务器上 单文件项目不利于SEO   也无法记录刷新/前进/后退
  ?     所以需要 改变url不请求服务器   监听url的变化执行对应的操作
  hash: 使用 hash 模式, 路径中会包含 # 符号, 默认模式
  ? 1. hash的改变不会去请求服务器 不会引起页面刷新
  ? 2. 触发hashchange事件
  ? 3. hash值变化会在浏览器的历史中留下记录, 使用的浏览器的后退按钮可以回到上一个hash值
  ? 4. hash永远不会提交到服务器, 即使刷新页面也不会
  history: 使用 history 模式, 路径中不会包含 # 符号, 需要后端支持
  ? 1. history模式：history.pushState()和replaceState() 可以记录与改变url同时, 不会刷新页面
  ? 2. history的变化不会触发任何事件,通过罗列可能触发history变化的情况, 对这些情况进行拦截, 以此监听history的变化
  ? 3. history模式的url发生变化时不会立即向服务器发起请求, 刷新会立即请求
  ? 4. 单页应用只有一个 html 文件, 服务端在处理其他路径的 url 的时候, 就会出现404的情况,如果 URL 匹配不到任何静态资源, 应该设置服务器返回单页应用的 html 文件
*/
export const history =
	import.meta.env.VITE_ROUTER_HISTORY === 'hash'
		? // 参数就是网站前缀，例如部署到 https://un-pany.github.io/v3-admin-vite/ 域名下，就需要填写 /v3-admin-vite/
			createWebHashHistory(import.meta.env.VITE_PUBLIC_PATH)
		: createWebHistory(import.meta.env.VITE_PUBLIC_PATH);

/** 路由降级（把三级及其以上的路由转化为二级路由） */
export const flatMultiLevelRoutes = (routes: RouteRecordRaw[]) => {
	const routesMirror = cloneDeep(routes);
	routesMirror.forEach((route) => {
		// 如果路由是三级及其以上路由, 对其进行降级处理
		isMultipleRoute(route) && promoteRouteLevel(route);
	});
	return routesMirror;
};

/** 判断路由层级是否大于 2 */
const isMultipleRoute = (route: RouteRecordRaw) => {
	const children = route.children;
	if (children?.length) {
		// 只要有一个子路由的 children 长度大于 0, 就说明是三级及其以上路由
		return children.some((child) => child.children?.length);
	}
	return false;
};

/** 生成二级路由 */
const promoteRouteLevel = (route: RouteRecordRaw) => {
	// 创建 router 实例是为了获取到当前传入的 route 的所有路由信息
	let router: Router | null = createRouter({
		history,
		routes: [route],
	});
	const routes = router.getRoutes();
	// 在 addToChildren 函数中使用上面获取到的路由信息来更新 route 的 children
	addToChildren(routes, route.children || [], route);
	router = null;
	// 转为二级路由后, 去除所有子路由中的 children
	route.children = route.children?.map((item) => omit(item, 'children') as RouteRecordRaw);
};

/** 将给定的子路由添加到指定的路由模块中 */
const addToChildren = (routes: RouteRecordNormalized[], children: RouteRecordRaw[], routeModule: RouteRecordRaw) => {
	children.forEach((child) => {
		const route = routes.find((item) => item.name === child.name);
		if (route) {
			// 初始化 routeModule 的 children
			routeModule.children = routeModule.children || [];
			// 如果 routeModule 的 children 属性中不包含该路由, 则将其添加进去
			if (!routeModule.children.includes(route)) {
				routeModule.children.push(route);
			}
			// 如果该子路由还有自己的子路由, 则递归调用此函数将它们也添加进去
			if (child.children?.length) {
				addToChildren(routes, child.children, routeModule);
			}
		}
	});
};
